/*
 * TODO language 
 * Copyright (c) 2010 TODO Team
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef TODO_OPCODES_H
#define TODO_OPCODES_H
#include <vector>
#include <map>
#include "types.h"
#include "executor.h"

namespace todo
{
typedef enum {
	TODO_ASSIGN = 0,
	TODO_DIV_ASSIGN,
	TODO_MULT_ASSIGN,
	TODO_ADD_ASSIGN,
	TODO_SUB_ASSIGN,
	TODO_MOD_ASSIGN,
	TODO_RETURN,
	TODO_DIV,
	TODO_MULT,
	TODO_ADD,
	TODO_SUB,
	TODO_MOD,
	TODO_DECL_VAR,
	TODO_DECL_FUNC,
	TODO_DECL_NS,
	TODO_PRINT,
	TODO_PRINTLN,
	TODO_CHG_VAR,
	TODO_END_FUNC,
	TODO_FUNC_CALL,
	TODO_IF,
	TODO_ELSIF,
	TODO_ELSE,
	TODO_ENDIF,
	TODO_METHOD_CALL
} todo_op_type;

struct todo_opcode {
	unsigned int op_num;
	todo_op_type type;
	TodoData op1, op2;	
	todo::handler_op handler;
	void *info;
	
	todo_opcode() : op1(TODO_UNUSED), op2(TODO_UNUSED), info(NULL), handler(NULL) { }
	
	todo_opcode(todo_op_type type_) : type(type_), op1(TODO_UNUSED), op2(TODO_UNUSED), info(NULL), handler(NULL) { }

	todo_opcode(todo_op_type type_, const TodoData& op1_) : type(type_), op2(TODO_UNUSED), info(NULL), handler(NULL) {
		set_op1(op1_);
	}
	
	todo_opcode(todo_op_type type_, const TodoData& op1_, const TodoData& op2_) : type(type_), info(NULL), handler(NULL) {
		set_op1(op1_);
		set_op2(op2_);
	}
	
	todo_opcode(const TodoData& op1_) : op2(TODO_UNUSED), info(NULL) {
		set_op1(op1_);
	}
	
	todo_opcode(const TodoData& op1_, const TodoData& op2_) : info(NULL) {
		set_op1(op1_);
		set_op2(op2_);
	}
	
	~todo_opcode() {
		free_info();
		
		if (op1.type != TODO_UNUSED &&
			(op1.type == TODO_CONSTANT || op1.type == TODO_VAR) &&
			op1.data.type == TODO_STRING &&
			op1.data.val.str) {
			delete op1.data.val.str;
		}
		if (op2.type != TODO_UNUSED &&
			(op2.type == TODO_CONSTANT || op2.type == TODO_VAR) &&
			op2.data.type == TODO_STRING &&
			op2.data.val.str) {
			delete op2.data.val.str;
		}
	}
	
	inline void set_type(todo_op_type type_) {
		type = type_;
	}
	
	inline void set_handler(const todo::handler_op& handler_) {
		handler = handler_;
	}
	
	inline void set_op1(const TodoData& op) {
		set_op(op1, op);
	}
	
	inline void set_op2(const TodoData& op) {
		set_op(op2, op);
	}

private:
	inline void set_op(TodoData& op, const TodoData& op_) {
		op.type = op_.type;
		op.data = op_.data;
		
		if (op.type != TODO_RET_VALUE && op.type != TODO_EXPR_VALUE) {
			if (op.data.type == TODO_STRING) {
				op.data.val.str = new std::string(*op_.data.val.str);
			}
		}
	}
	
	void free_info();
};

class TodoOpcodes {
public:
	std::vector<todo_opcode*> list;
	
	TodoOpcodes() { };
	~TodoOpcodes() { };
	
	void add(todo_opcode* opcode);
	todo_opcode* get_last(void);
	int get_num(void) const;
	todo_opcode* get_opcode(unsigned int op_num);
	void free(void);
	// Debug
	const std::string get_name(todo_op_type type) const;
	const std::string get_type(const TodoData& value) const;
	const std::string get_value(const TodoValue& value) const;	
	void dump(void);
	void dump(todo_opcode*& op) const;
	void dump_op(const TodoData& op) const;
};
} // todo

extern todo::TodoOpcodes ops;

#endif // TODO_OPCODES_H
